15-112 Fundamentals of Programming

Homework 5.1


For this homework, there is no starter file. You have to create your own .py file and submit it to Autolab. You can take a previous starter file and modify it appropriately.

  • Please add your name, Andrew id, and section at the top of the file.
  • APPLY TOP-DOWN DESIGN, USE LOTS OF HELPER FUNCTIONS.
  • Parts of this homework will be manually graded.
  • You will be graded on style. You can lose up to 10 poins for style (out of 100 points). Please see here for the style rubric.


  • Important instructions
    1. This hw has two parts -- hw51a covers OOP (with some animation) and hw51b covers recursion. Note that you may (and should) use iteration (while and for loops) in hw51a, but you may not use iteration in hw51b. Be sure to submit hw51a.py and hw51b.py separately (there will be separate autolab assignments for each part).
    2. Each part uses up to 1 grace day separately. Thus, if you submit both parts on Friday, you would use 2 separate grace days.
    3. If you know what itertools are, don't use them to get around using recursion. If you don't know what itertools are, you may safely ignore this item.
    4. Portions of this hw are autograded. You may make up to 5 submissions each of hw51a and hw51b. As usual, only your last one counts.

    Questions

    Hw5.1a: TP + OOP

    1. 5-Minute TP Meetings [10pts] [manually graded]

    By hw 5.1's deadline, everyone must have completed a 5-minute meeting (yes, just 5 minutes, though they may expand to 10 minutes at your TA's discretion) with one of the TA's from your assigned recitation, to begin a discussion about your term project ideas. This is very brief, just to be sure you've started thinking about TP's at least a bit. You do not have to prepare for these meetings, but it would be nice (and probably more effective) if you showed up with some ideas about what you might want to pursue.

    Early in this hw cycle, you will receive an email from your TA's with instructions about how to sign up for these meetings. Be sure to sign up right away, and be sure to be on time to these meetings. And move quickly, since they will be kept to 5 minutes, for real. So you know: They are worth 10 points in hw5.1, and the only way to get the points is to be on time. If you are late, or if you miss the meeting, you will not get the points, even if you have a make-up meeting. Of course, this does not include students with hw5.1 extensions for university-approved conflicts, or documented medical emergencies, etc.

    These meetings are only to help you. But you can help yourself, too. Look over the gallery a bit. Get an idea of what constitutes a term project. And start thinking about what you might be interested in.

    2. Polynomial and Quadratic classes [40 pts][autograded]

    Starting from the Polynomial class here, edit that class and also implement the Quadratic class so that all the tests below succeed. Be sure not to hardcode against these tests, as the autograder will use similar tests, but with different constants. You are also responsible for understanding how the tests themselves work. For example, understand how the list of first-class functions is being used in testPolynomialAndQuadraticClasses, and also understand why the try/except calls are used in testQuadraticClass. Good luck!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    def testPolynomialAndQuadraticClasses():
        print("Testing Polynomial and Quadratic classes...")
        for testFn in [testPolynomialBasics,
                       testPolynomialEq,
                       testPolynomialStr,
                       testPolynomialConstructor,
                       testPolynomialInSets,
                       testPolynomialTimesOperator,
                       testPolynomialExponentiationOperator,
                       testQuadraticClass
                      ]:
            print("  Running %s..." % testFn.__name__, end = " ")
            testFn()
            print("Passed!")
        print("Passed all Polynomial and Quadratic Class tests!")
      
    def almostEqual(d1, d2):
        epsilon = 0.000001
        return abs(d1 - d2) < epsilon
      
    def testPolynomialBasics():
        p1 = Polynomial([2, -3, 5])  # 2x**2 -3x + 5
        assert(type(p1) == Polynomial)
        assert(p1.degree() == 2)
        assert(p1.coeff(0) == 5)
        assert(p1.coeff(1) == -3)
        assert(p1.coeff(2) == 2)
        assert(p1.evalAt(0) == 5)
        assert(p1.evalAt(2) == 7)
        p2 = Polynomial([4, -3])
        # Now test the + operator
        p3 = p1 + p2 # (2x**2 -3x + 5) + (4x - 3) == (2x**2 + x + 2)
        assert(type(p3) == Polynomial)
        assert(p3.evalAt(2) == 12)
        assert(p3.evalAt(5) == 57)
      
    def testPolynomialEq():
        assert(Polynomial([1,2,3]) == Polynomial([1,2,3]))
        assert(Polynomial([1,2,3]) != Polynomial([1,2,3,0]))
        assert(Polynomial([1,2,3]) != Polynomial([1,2,0,3]))
        assert(Polynomial([1,2,3]) != Polynomial([1,-2,3]))
        assert(Polynomial([1,2,3]) != 42)
        assert(Polynomial([1,2,3]) != "Wahoo!")
        # A polynomial of degree 0 has to equal the same non-Polynomial numeric!
        assert(Polynomial([42]) == 42)
      
    def testPolynomialStr():
        assert(str(Polynomial([1,2,3])) == "x^2 + 2x + 3")
        assert(str(Polynomial([-1,-2,-3])) == "-x^2 - 2x - 3")
        assert(str(Polynomial([42])) == "42")
        assert(str(Polynomial([-42])) == "-42")
        assert(str(Polynomial([0])) == "0")
        assert(str(Polynomial([1,0,-3, 0, 1])) == "x^4 - 3x^2 + 1")
        assert(str(Polynomial([1,0,-3, 0, 1])) == "x^4 - 3x^2 + 1")
        assert(str(Polynomial([-1,0,3, 0, -1])) == "-x^4 + 3x^2 - 1")
      
    def testPolynomialConstructor():
        # If the list is empty, treat it the same as [0]
        assert(Polynomial([]) == Polynomial([0]))
        assert(Polynomial([]) != Polynomial([1]))
        # Remove leading 0's
        assert(Polynomial([0,0,0,1,2]) == Polynomial([1,2]))
        assert(Polynomial([0,0,0,1,2]).degree() == 1)
        # Require that the constructor be non-destructive
        coeffs = [0,0,0,1,2]
        assert(Polynomial(coeffs) == Polynomial([1,2]))
        assert(coeffs == [0,0,0,1,2])
      
    def testPolynomialInSets():
        s = set()
        assert(Polynomial([1,2,3]) not in s)
        s.add(Polynomial([1,2,3]))
        assert(Polynomial([1,2,3]) in s)
        assert(Polynomial([1,2,3]) in s)
        assert(Polynomial([1,2]) not in s)
      
    def testPolynomialTimesOperator():
        # (x**2 + 2)(x**4 + 3x**2) == (x**6 + 5x**4 + 6x**2)
        assert(Polynomial([1,0,2]) * Polynomial([1,0,3,0,0]) ==
               Polynomial([1,0,5,0,6,0,0]))
        # (x**3 - 3x + 5) * 10 == (10x**3 - 30x + 50)
        assert(Polynomial([1,0,-3,5]) * 10 == Polynomial([10,0,-30,50]))
        # Hint: to do multiplication this way, you have to use __rmul__,
        # which should just call __mul__ (yes, really)
        assert(10 * Polynomial([1,0,-3,5]) == Polynomial([10,0,-30,50]))
      
    def testPolynomialExponentiationOperator():
        assert(Polynomial([1,2,3])**0 == 1)
        assert(Polynomial([1,2,3])**1 == Polynomial([1,2,3]))
        assert(Polynomial([1,2,3])**2 == Polynomial([1,2,3]) * Polynomial([1,2,3]))
        assert(Polynomial([1,2,3])**3 == Polynomial([1,2,3]) * Polynomial([1,2,3]) * Polynomial([1,2,3]))
      
    def testQuadraticClass():
        q1 = Quadratic([3,2,1])  # 3x^2 + 2x + 1
        assert(type(q1) == Quadratic)
        assert(q1.evalAt(10) == 321)
        assert(isinstance(q1, Quadratic) == isinstance(q1, Polynomial) == True)
        # the determinant is b**2 - 4ac
        assert(q1.determinant() == -8)
        # use the determinant to determine how many real roots (zeroes) exist
        assert(q1.numberOfRealRoots() == 0)
        assert(q1.getRealRoots() == [ ])
        # Once again, with a double root
        q2 = Quadratic([1,-6,9])
        assert(q2.determinant() == 0)
        assert(q2.numberOfRealRoots() == 1)
        [root] = q2.getRealRoots()
        assert(almostEqual(root, 3))
        # And again with two roots
        q3 = Quadratic([1,1,-6])
        assert(q3.determinant() == 25)
        assert(q3.numberOfRealRoots() == 2)
        [root1, root2] = q3.getRealRoots() # smaller one first
        assert(almostEqual(root1, -3) and almostEqual(root2, 2))
        # And make sure that these methods were defined in the Quadratic class
        # and not in the Polynomial class (we'll just check a couple of them...)
        assert('evalAt' in Polynomial.__dict__)
        assert('evalAt' not in Quadratic.__dict__)
        assert('determinant' in Quadratic.__dict__)
        assert('determinant' not in Polynomial.__dict__)
      
    testPolynomialAndQuadraticClasses()

    3. OOPy Flappy Bird [30 pts][manually graded]

    During last's week recitation, we developed the animation for flappy bird. If you have forgotten how Flappy Bird Animation works, here is an implementation. Note though that instead of using the mouse to keep the bird flapping, we've used the Space bar.

    Here, we want to re-write the flappy bird animation using objects. You should create two classes: The Bird Class and the Obstacle Class. The Bird class should have at least a draw() and move() method, while the Obstacle Class should have at least a draw(), move(), and isColliding() method.

    In addition, as we mentioned in lecture, the attributes of an object should never be directly changed, so make good use of observer methods and modifier methods. If you fail to adhere to this, you will loose points.

    Here's a few more specifications/features for this game:

    1. Include a splash screen that shows a main menu with some initial instructions when the animation is first run and then allow the user to switch to the play mode when pressing any key.
    2. Include a 'help' screen mode, which pauses the game and takes the user to a help screen with some useful instructions for the gameplay when the user presses 'h'.
    3. Include a reset feature, where the game starts over when the player presses 'r'.

    Make sure to put all of the animation code for Flappy bird below the #ignore_rest line!

    Hw5.1b: Recursion

    4. interleave(s1, s2) [10 pts][autograded]

    Without using any iteration, write the function interleave(s1, s2) that takes two strings, s1 and s2, and interleaves their characters starting with the first character in s1. For example, interleave('pto', 'yhn') would return the string "python". If one string is longer than the other, concatenate the rest of the remaining string onto the end of the new string. For example, ('a#', 'cD!f2') would return the string "ac#D!f2".

    5. isPerfectNumber(n) [10 pts][autograded]

    Without using any iteration, write the function isPerfectNumber that takes a possibly-negative integer n and returns True if it is a perfect number and False otherwise, where a number is perfect if it is the sum of its positive divisors less than itself. We'll assume 0 is perfect. The next perfect number is 6 because 6 = 1 + 2 + 3. The next one is 28 because 28 = 1 + 2 + 4 + 7 + 14. The next one is 496, then 8128, ...


    Valid CSS! Valid XHTML 1.0 Strict